mmt - denken in knopen
Knopen
Vooraleer we met React begonnen, hebben we een webpagina bekeken vanuit het standpunt van een HTML document. Een platte tekst met daarin HTML element.
Als we de webpagina interactief willen maken hebben we geleerd dat de DOM het document als knooppunten van objecten voorstelt. Op die manier kunnen we de platte HTML tekst bewerken met behulp van JavaScript. De DOM is een objectgeoriënteerde weergave van de webpagina, die kan worden gewijzigd met een scripttaal zoals JavaScript.
Als we met React werken is het vertrekpunt niet meer het HTML document maar de DOM voorstelling van de HTML elementen, dwz knopen van objecten die op hun beurt weer objecten zijn. React creëert een virtuele DOM en rendert die in de browser.
Als we webpagina's ontwikkelen met React moeten we van invalshoek veranderen. Niet meer denken in HTML elementen maar in HTML objecten en knooppunten.
We ontwikkelen een webapplicatie waarmee je artikelen kan aanbieden aan de gebruiker. Dat kunnen om het even welke artikelen zijn, van fietsen, petten tot boeken. Als voorbeeld ontwikkelen we een reisapplicatie. De website heeft een overzicht van alle dolmens en menhirs in de Sarthe in Frankrijk.
- De
ArticleSummary
knoop
Deze knoop bevat de samenvatting van het artikel.- wireframe
- technische analyse
- De afbeelding en de knop staan onder elkaar. Het
article
element maken we dusflex
en de richting stellen we in opcolumn
. - De stijl voor de
Article
tag plaatsen we in de functie-component omdat we die alleen daar gaan gebruiken. - We hergebruiken onze
AButton
functie-component. - We maken een ui-article.js bestand om alle ui elementen in zetten die met het mmt project te maken te maken.
- We hergebruiken ui-controls.js maar schonen het op. We houden alleen die controls over die we gaan gebruiken. Ik heb de namen van style constanten wel hernoemd.
buttonStyle
enlabelStyle
zijn gewoonstyle
geworden. Die constanten staat in een functie-component en kunnen dus dezelfde naam hebben. - En we voegen er een
ImageSummary
control aan toe in de vorm van een functie-component. Deze component dient om een afbeelding in klein formaat te tonen:
- De afbeelding en de knop staan onder elkaar. Het
- denken in knopen
- die wireframe bestaat uit twee knopen, een button knoop en een image knoop.
Abutton
knoop:
We hebben al eenAbutton
functie-component gemaakt. We gaan die hergebruiken. We hernoemen alleen debuttonStyle
constante naarstyle
. We hoeven daar geen button aan toe te voegen omdat destyle
in een functie-component staat.ImageSummary
knoop
We maken een image knoop met de naamImageSummary
:function ImageSummary(props) { const style = { borderRadius: "6px", } return (<img style={style} alt={`afbeelding van ${props.name}`} src={props.image} /> ); }
- De
ArticleSummary
knoop is samengesteld uit de 2 knopen van hierboven.- code:
function ArticleSummary(props) { const style = { display: "flex", flexDirection: "column", width: "10em" } return (<article style={style}> <ImageOverview name={props.name} image={props.image}/> <AButton caption={props.name}/> </article>); }
- renderen in index.html:
<body> <div id="root"></div> <script type="text/babel"> ReactDOM.render(<ArticleSummary name="Allée couverte du Colombier" image="images/small/Allee couverte du Colombier.jpg" />, document.querySelector('#root')) </script> </body>
- resultaat:
- code:
- die wireframe bestaat uit twee knopen, een button knoop en een image knoop.
- Een
ArticleOverview
knoop- wireframe
- denken in knopen
ArticleHeader
- Let erop hoe we een styled component maken. De CSS stijl bestaat uit een
style
object van drie objecten, eenheader
, eentitle
en eenlogo
subobject. Er zijn vier mogelijkheden om CSS toe te passen op componenten. We gebruiken hier Inline styling.In React worden inline stijlen niet gespecificeerd als een string. In plaats daarvan worden ze gedefinieerd als een object waarvan de sleutels de camelCased-versie van de CSS-stijleigenschap is en waarvan de waarde de waarde van de stijl is, meestal een tekenreeks. - We gaan die component op elke pagina van de website gebruiken.
- code:
function ArticleHeader(props) { const style = { header: { display: "flex", flexDirection: "row", justifyContent: "space-between", width: "100%", heigth: "10em" }, title: { alignSelf: "center", fontFamily: "Arial", color: "red", paddingRight: "1em" }, logo: { height: "10em" } } return (<header style={style.header}> <img alt={`Logo ${props.title}`} src={props.image} style={style.logo}/> <h1 style={style.title}>{props.title}</h1> </header>); }
- uitproberen in index.html:
<body> <div id="root"></div> <script type="text/babel"> ReactDOM.render(<ArticleHeader title="Moe maar tevreden" image="images/mmt-logo.png" />, document.querySelector('#root')) </script> </body>
- Resultaat:
- We halen de lijst van de bezienswaardigheden uit het JSON bestand in te lezen. Zie hiervoor: JSON - bestand inlezen met Fetch API. We doen dat in index.html. Eerst proberen we het JSON bestand in te lezen en als het lukt renderen we de ArticleHeader component. De titel en de url voor het logo halen we uit het JSON object:
<body> <div id="root"></div> <script type="text/babel"> const url = 'data/neolithicum.json'; const myRequest = new Request(url); fetch(myRequest) .then(response => response.json()) .then(data => { ReactDOM.render(<ArticleHeader title={data.title} image={data.logoUrl} />, document.querySelector('#root')); }) .catch(response => alert("Kan JSON bestand niet openen.")); </script> </body>
- Resultaat:
Nu staat de titel uit het JSON bestand erin:
- Let erop hoe we een styled component maken. De CSS stijl bestaat uit een
- Een
ArticleOverview
knoop- Een lijst van
ArticleSummary
componenten. Voor elk item van de het cusiosity array van objecten maken we eenArticleSummary
component:function ArticleOverview(props) { const style = { color: 'white', display: 'flex', flexWrap: 'wrap' }; // alert(JSON.stringify(props)); return ( <main> <div style={style}> {props.article.map(item => (<ArticleSummary item={item} key={item.key} action={props.action} />))} </div> </main> ); }
- Een lijst van
- Een
ArticleDetail
knoop- wireframe
- denken in knopen
- de wireframe kunnen we opdelen in verschillende knopen:
- een ongeordende lijst met de tekstbeschrijving
- een afbeelding
- een kaart
- een label voor de titel
- een LikePanel
- een tekstveld en Submit knop
- een lijst met de commentaren
- een knop om terug te keren naar het overzicht
- code:
class ArticleDetail extends React.Component { style = { detail: { display: "flex", flexDirection: "column", width: "70%" }, top: { display: "flex", flexDirection: "row" }, middle: { display: "flex", flexDirection: "row" }, comment: { display: "block" } } constructor(props) { super(props); } componentDidMount() { this.leafLetView('leaflet-id'); } showOverview = () => { this.props.actionOverview() } leafLetView = (id) => { // Initialiseert de mijnKaart constante const map = L.map(id); // Laad de basiskaart const baseMap = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>', }); // plaats de basismap in het html element met id = kaart-id baseMap.addTo(map); // Stel het gebied van de kaart in // de laatste parameter bepaalt de grootte van het getoonde gebied // hoe groter het getal, hoe gedetailleerder // alert(this.props.article.longitude); const pos1 = this.props.article.longitude.substr(0, 5); const pos2 = this.props.article.latitude.substr(0, 5); const mark = L.marker([this.props.article.latitude, this.props.article.longitude]).addTo(map); // alert(pos1 + pos2); map.setView([pos2, pos1], 12); } render() { return (<article style={this.style}> <AButton caption="Terug naar overzicht" onClick={this.showOverview} /> <div style={this.style.top}> <ImageDetail name={this.props.article.name} image={`images/big/${this.props.article.image}`} /> <LeafLetNode /> </div> <div style={this.style.middle}> <div> <ul> <li>{this.props.article.name}</li> <li>{this.props.article.type}</li> <li>{this.props.article.period}</li> <li>{this.props.article.country}</li> <li>{this.props.article.region}</li> <li>{this.props.article.city}</li> </ul> </div> <div> <ul> <li>{this.props.article.coordinates}</li> <li>{this.props.article.longitude}</li> <li>{this.props.article.latitude}</li> </ul> <LikePanel /> </div> </div> <textarea style={this.style.comment}></textarea> <AButton caption="Verzenden" /> </article>); } }
- ArticleApp
- Technische beschrijving
De eigenlijk app knoop die ook dienst doet als controller. Daar houden we de state bij. Hiermee weten we als we de pagina opnieuw moeten renderen. In het geval de gebruiker op één artikel heeft geklikt of terug naar het overzicht wilt. - Code:
class ArticleApp extends React.Component { constructor(props) { super(props); this.state = { overview: true }; } showDetail = (item) => { this.setState({ overview: false, article: item }); }; showOverview = () => { this.setState({ overview: true, article: null }); }; render() { if (this.state.overview) { return ( <ArticleOverview article={this.props.article} action={this.showDetail} /> ); } else { return (<ArticleDetail article={this.state.article} actionOverview={this.showOverview} />) } } }
- Tenslotte de index.html pagina:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> <script type="text/babel" src="js/ui-controls.js"></script> <script type="text/babel" src="js/ui-article.js"></script> <link crossorigin="" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" rel="stylesheet" /> <script crossorigin="" integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew==" src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"></script> <title>Moe maar tevreden</title> </head> <body> <header id="header"></header> <div id="root"></div> <script type="text/babel"> const url = 'data/neolithicum.json'; const myRequest = new Request(url); fetch(myRequest) .then(response => response.json()) .then(data => { ReactDOM.render(<ArticleHeader title={data.title} image={data.logoUrl} />, document.querySelector('#header')); ReactDOM.render(<ArticleApp article={data.curiosity} />, document.querySelector('#root')); }) .catch(response => alert(response)); </script> </body> </html>
- Technische beschrijving